var JForm = {};
JForm.trim = function(s){return (s != null ? new String(s).replace(/(^\s*)|(\s*$)/g, "") : "");}

JForm.create = function(form, parameters){
    var debug = (parameters.debug == true);

    if(form != null && parameters != null) {
        var type = (debug ? "text" : "hidden");

        for(var i in parameters) {
            var name = i;
            var text = null;
            var value = parameters[i];

            if(name != "debug" && value != null) {
                var className = typeof(value);

                if(className == "string" || className == "number" || className == "boolean") {
                    text = this.createTextElement(type, name, value);
                    form.appendChild(text);
                }
                else if(className == "object" && value.length != null) {
                    for(var j = 0; j < value.length; j++) {
                        if(value[j] != null) {
                            text = this.createTextElement(type, name, value[j]);
                            form.appendChild(text);
                        }
                    }
                }
                else {
                    text = this.createTextElement(type, name, value);
                    form.appendChild(text);
                }
            }
        }

        if(debug == true) {
            var text = this.createTextElement(type, "DEBUG", debug);
            form.appendChild(text);
        }
    }
};

JForm.createTextElement = function(type, name, value){
    var text = null;

    if(document.all) {
        text = document.createElement("<input type=\"" + type + "\" name=\"" + name + "\"/>");
    }
    else {
        text = document.createElement("input");
        text.type = type;
        text.name = name;
    }

    text.title = name;
    text.value = (value != null ? value : "");
    return text;
};

JForm.serialize = function(json){
    if(json == null) {
        return "";
    }

    if(typeof(json) != "object") {
        return "";
    }

    var a = [];

    for(var name in json) {
        var value = json[name];
        var className = typeof(value);

        if(value != null) {
            if(className == "object" && value.length != null) {
                for(var j = 0; j < value.length; j++) {
                    if(value[j] != null) {
                        a[a.length] = encodeURIComponent(name) + "=" + encodeURIComponent(value[j]);
                    }
                }
            }
            else {
                a[a.length] = encodeURIComponent(name) + "=" + encodeURIComponent(value.toString());
            }
        }
    }

    return a.join("&");
};

JForm.clear = function(form){
    form.innerHTML = "";
};

JForm.submit = function(request){
    var form = request.form;
    var parameters = request.parameters;

    if(form == null) {
        var formId = "__jform__";
        form = document.getElementById(formId);

        if(form == null) {
            form = document.createElement("form");
            form.id = formId;
            document.body.appendChild(form);
        }
    }

    form.action = (request.action || "");
    form.method = (request.method || "get");

    if(request.enctype != null) {
        form.enctype = request.enctype;
    }

    if(request.target != null) {
        form.target = request.target;
    }
    else {
        form.target = "";
    }

    JForm.clear(form);
    JForm.create(form, parameters);

    if(parameters.debug != true) {
        form.submit();
    }
};

var SimpleParser = {};

SimpleParser.parse = function(source) {
    var k = source.indexOf("(");
    var method = null;
    var parameters = null;

    if(k > -1) {
        method = source.substring(0, k);
        parameters = source.substring(k);
    }
    else {
        throw new Error(0, code);
    }

    k = method.lastIndexOf(".");
    var serviceName = null;
    var methodName = null;

    if(k > -1) {
        serviceName = method.substring(0, k);
        methodName = method.substring(k + 1);
    }

    var fun = function(){
        var args = [];
        var cast = function(value){
            var className = typeof(value);

            if(value == null || value == undefined || className == "undefined") {
                return null;
            }
            else if(className == "string" || className == "boolean") {
                return value;
            }
            else if(className == "number") {
                if(isNaN(value)) {
                    return null;
                }
                else {
                    return value;
                }
            }
            else if(className == "function") {
                return arguments.callee(value());
            }
            else {
                return JSON.stringify(value);
            }
        };

        for(var i = 0; i < arguments.length; i++) {
            args[i] = cast(arguments[i]);
        }

        return args;
    };

    var code = "(" + fun.toString() + ")" + parameters;
    var invocation = {"serviceName": serviceName, "methodName": methodName, "parameters": eval(code)};
    return invocation;
};

SimpleParser.build = function(invocation){
    var buffer = [];
    var serviceName = invocation.serviceName;
    var methodName = invocation.methodName;
    var parameters = invocation.parameters;

    for(var i = 0; i < parameters.length; i++) {
        var value = parameters[i];
        var className = typeof(value);

        if(value == null || value == undefined || className == "undefined") {
            buffer[buffer.length] = "null";
        }
        else if(className == "number") {
            if(isNaN(value)) {
                buffer[buffer.length] = "null";
            }
            else {
                buffer[buffer.length] = value;
            }
        }
        else if(className == "boolean") {
            buffer[buffer.length] = value;
        }
        else {
            buffer[buffer.length] = "\"" + Client.escape(value.toString()) + "\"";
        }
    }
    return serviceName + "." + methodName + "(" + buffer.join(", ") + ");";
};

SimpleParser.getCode = function(f){
    var source = f.toString();
    source = source.replace(new RegExp("/\\*.*\\*/", "g"), "");
    source = source.replace(new RegExp("//[^\n]*\\n", "g"), "\n");
    source = Client.trim(source);

    if(source.charAt(source.length - 1) == ";") {
        source = Client.trim(source.substring(0, source.length - 1));
    }

    var regExp = new RegExp("[ ]*function[ ]*\\([ ]*\\)[ ]*\\{([\\s\\S]*)\\}$");
    var arr = regExp.exec(source);

    if(arr != null && arr.length > 0) {
        var content = Client.trim(arr[1]);
        var result = content.split("\n");
        var code = null;

        if(result.length > 0) {
            code = Client.trim(result[result.length - 1]);
        }
        else {
            code = code;
        }

        if(code.length >= 1 && code.charAt(0) == "$") {
            code = "@" + code.substring(1);
        }
        return code;
    }
    else {
        return null;
    }
};

var Client = {};

Client.trim = function(s){return (s != null ? new String(s).replace(/(^\s*)|(\s*$)/g, "") : "");}
Client.escape = function(source){
    if(source == null) {
        return "";
    }

    var c;
    var buffer = [];

    for(var i = 0, length = source.length; i < length; i++) {
        c = source.charAt(i);

        switch (c) {
            case "\'": {
                buffer[buffer.length] = "\\\'";
                break;
            }
            case "\"": {
                buffer[buffer.length] = "\\\"";
                break;
            }
            case "\r": {
                buffer[buffer.length] = "\\r";
                break;
            }
            case "\n": {
                buffer[buffer.length] = "\\n";
                break;
            }
            case "\t": {
                buffer[buffer.length] = "\\t";
                break;
            }
            case "\b": {
                buffer[buffer.length] = "\\b";
                break;
            }
            case "\f": {
                buffer[buffer.length] = "\\f";
                break;
            }
            case "\\": {
                buffer[buffer.length] = "\\\\";
                break;
            }
            default: {
                buffer[buffer.length] = c;
                break;
            }
        }
    }
    return buffer.join("");
};

Client.getValue = function(id){
    var e = document.getElementById(id);

    if(e != null) {
        return e.value;
    }

    return null;
};

Client.parse = function(source){
    Client.clear();

    if(source == null || Client.trim(source).length < 1) {
        return;
    }

    try {
        var invocation = SimpleParser.parse(source);
        var parameters = invocation.parameters;
        Client.create("serviceName", invocation.serviceName, false);
        Client.create("methodName", invocation.methodName, false);

        if(parameters.length > 0) {
            for(var i = 0; i < parameters.length; i++) {
                Client.create("param" + i, parameters[i]);
            }
        }
    }
    catch(e) {
        alert(e.name + ": " + e.message);
    }
};

Client.build = function(form){
    Client.clear();
    Client.setAction(form.action);
    Client.setHttpMethod(form.method);
    var parameters = form.data;

    if(parameters != null && typeof(parameters) == "object") {
        for(var name in parameters) {
            var value = parameters[name];

            if(value != null) {
                var className = typeof(value);

                if(className == "object" && value.length != null) {
                    for(var j = 0; j < value.length; j++) {
                        if(value[j] != null) {
                            Client.create(name, value[j]);
                        }
                    }
                }
                else {
                    Client.create(name, value.toString());
                }
            }
        }
    }
};

Client.create = function(name, value, editable){
    var table = document.getElementById("clientTable");

    if(table != null) {
        var tr = table.insertRow(-1);
        var td1 = tr.insertCell(-1);
        var td2 = tr.insertCell(-1);
        var td3 = tr.insertCell(-1);
        var td4 = tr.insertCell(-1);

        if(editable != false) {
            td1.innerHTML = "<input type=\"checkbox\" name=\"c1\"/>";
            td2.innerHTML = "<input type=\"text\" class=\"text2\" name=\"pname\"/>";
            td3.innerHTML = "<input type=\"text\" class=\"text2\" name=\"pvalue\"/>";
            td3.innerHTML = "<input type=\"text\" class=\"text2\" name=\"pvalue\"/>";
            td4.innerHTML = "<input type=\"button\" class=\"button\" value=\" 删除 \" onclick=\"this.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode);\"/>";
        }
        else {
            td1.innerHTML = "<input type=\"checkbox\" name=\"c1\" disabled=\"true\"/>";
            td2.innerHTML = "<input type=\"text\" class=\"text2 disabled\" name=\"pname\" readonly=\"true\"/>";
            td3.innerHTML = "<input type=\"text\" class=\"text2 disabled\" name=\"pvalue\" readonly=\"true\"/>";
            td3.innerHTML = "<input type=\"text\" class=\"text2\" name=\"pvalue\"/>";
            td4.innerHTML = "<input type=\"button\" class=\"button disabled\" disabled=\"true\" value=\" 删除 \"/>";
        }

        tr.className = "h24";
        td1.className = "c1 h24 center";
        td2.className = "w200";
        td3.className = "auto";
        td4.className = "w100 center";

        if(name != null) {
            td2.childNodes[0].value = name;
        }

        if(value != null) {
            td3.childNodes[0].value = value;
        }
    }
};

Client.clear = function(){
    var table = document.getElementById("clientTable");

    if(table != null) {
        var rows = table.rows;
        var size = rows.length;

        for(var i = size - 1; i > 0; i--) {
            var e = rows[i];
            e.parentNode.removeChild(e);
        }
    }
};

Client.remove = function(){
    var list = document.getElementsByName("c1");

    if(list.length == null || list.length == undefined) {
        if(list.checked == true) {
            list.parentNode.parentNode.parentNode.removeChild(list.parentNode.parentNode);
        }
        return;
    }

    var temp = [];

    for(var i = 0; i < list.length; i++) {
        var n = list[i];

        if(n.checked == true) {
            temp[temp.length] = n;
        }
    }

    for(var i = 0; i < temp.length; i++) {
        var n = temp[i];
        n.parentNode.parentNode.parentNode.removeChild(n.parentNode.parentNode);
    }
};

Client.getHttpMethod = function(){
    return "post";
};

Client.getAction = function(id){
    return window.location.pathname.replace("/demon.html", "/demon/invoke.html");
};

Client.getParameters = function(){
    var parameters = {};
    var table = document.getElementById("clientTable");

    if(table != null) {
        var rows = table.rows;
        var size = rows.length;

        for(var i = 0; i < size; i++) {
            var name = Client.trim(rows[i].cells[1].childNodes[0].value);
            var value = rows[i].cells[2].childNodes[0].value;

            if(name != "") {
                var values = parameters[name];

                if(values == null) {
                    values = parameters[name] = [];
                }
                values[values.length] = value;
            }
        }
    }
    return parameters;
};

Client.submit = function(){
    var action = Client.getAction();
    var method = Client.getHttpMethod();

    if(action != null) {
        var parameters = Client.getParameters();

        JForm.submit({
            "method": method,
            "action": action,
            "target": "_blank",
            "parameters": parameters
        });
    }
};

Client.show = function(invocation) {
    if(invocation.execute == null) {
        throw new Error("the 'execute' method not exists !");
    }

    var code = SimpleParser.getCode(invocation.execute);
    document.getElementById("source").value = code;
    Client.parse(code);

    if(invocation.parameterTypes != null) {
        Client.create("parameterTypeList", invocation.parameterTypes);
    }
};

Client.getSource = function() {
    var source = document.getElementById("source").value;
    source = source.replace(new RegExp("/\\*.*\\*/", "g"), "");
    source = source.replace(new RegExp("//[^\n]*\\n", "g"), "\n");
    source = Client.trim(source);

    if(source.charAt(source.length - 1) == ";") {
        source = Client.trim(source.substring(0, source.length - 1));
    }
    return source;
};

var MethodInvocation = function(method, action, target, serviceName, methodName, parameterTypes) {
    this.method = method;
    this.action = action;
    this.target = target;
    this.serviceName = serviceName;
    this.methodName = methodName;
    this.parameterTypes = parameterTypes;
};

MethodInvocation.prototype.getParameters = function(){
    var args = [];
    var cast = function(value){
        var className = typeof(value);

        if(value == null || value == undefined || className == "undefined") {
            return null;
        }
        else if(className == "string" || className == "boolean") {
            return value;
        }
        else if(className == "number") {
            if(isNaN(value)) {
                return null;
            }
            else {
                return value;
            }
        }
        else if(className == "function") {
            return arguments.callee(value());
        }
        else {
            return JSON.stringify(value);
        }
    };

    for(var i = 0; i < arguments.length; i++) {
        args[i] = cast(arguments[i]);
    }

    return args;
};

MethodInvocation.prototype.getProxy = function(name){
    if(name != null) {
        var k = name.lastIndexOf(".");

        if(k > -1) {
            this.serviceName = method.substring(0, k);
            this.methodName = method.substring(k + 1);
        }
    }

    var proxy = this;
    var methodName = this.methodName;

    if(methodName != null && proxy[methodName] == null) {
        proxy[methodName] = function(){
            this.invoke.apply(this, arguments)
        };
    }

    return this;
};

MethodInvocation.prototype.invoke = function(){
    var args = {};
    var method = this.method;
    var action = this.action;
    var target = this.target;
    var parameters = this.getParameters.apply(this, arguments);
    args.serviceName = this.serviceName;
    args.methodName = this.methodName;

    if(this.parameterTypes != null) {
        args.parameterTypeList = this.parameterTypes;
    }

    if(parameters.length > 0) {
        for(var i = 0; i < parameters.length; i++) {
            args["param" + i] = parameters[i];
        }
    }

    JForm.submit({
        "method": method,
        "action": action,
        "target": target,
        "parameters": args
    });
};

var ServiceFactory = {};

ServiceFactory.create = function(invocation){
    var service = new MethodInvocation();
    service.method = invocation.method;
    service.action = invocation.action;
    service.target = invocation.target;
    service.serviceName = invocation.serviceName;
    service.methodName = invocation.methodName;
    service.parameterTypes = invocation.parameterTypes;
    return service.getProxy();
};

jQuery(function() {
    jQuery("#source").change(function(){
        Client.parse(Client.getSource());
    });

    jQuery("#parse-btn").click(function() {
        jQuery("#source").change();
    });

    jQuery("#execute-btn").click(function(){
        Client.submit();
    });

    /**
     * 添加删除
     */
    jQuery("#add-btn").click(function(){
        Client.create();
    });

    jQuery("#del-btn").click(function(){
        Client.remove();
    });
    jQuery("#parse-btn").click();
});
